<script setup lang="ts">
import { ref, watch, computed, nextTick } from 'vue'
import type { FormInstance, FormRules } from 'element-plus'
import { addRole, updateRole, getRole, roleMenuTreeselect } from '@/common/apis/system/role'
import { ElMessage } from 'element-plus'
import { treeselect } from '@/common/apis/system/menu'
import { cloneDeep, isEqual } from "lodash-es"
import { CheckboxValueType } from 'element-plus'
const props = defineProps<{
  dialogShow: boolean
  id: string
}>()
const dialogVisible = ref(false)
const emit = defineEmits(['update:dialogShow'])
const formData = ref({
  roleName: '',
  roleKey: '',
  status: '0',
  remark: '',
  menu: '',
  roleSort: '',
  menuIds: []
})
const defaultProps = {
  children: 'children',
  label: 'label',
}
interface TreeData {
  id: number
  label: string
  children: TreeData[]
}
const treeData = ref<TreeData[]>([])
// 树形结构
const testingTree = ref()
// 全选
const checkedAll = ref(false)
// 展开/折叠
const showAll = ref(false)
// 表单
const ruleFormRef = ref<FormInstance>()
const defaultCheckedKeys = ref([])
// 是否详情
const isDetail = ref(false)
// 文本
const textMap = ref('新增角色')
// 保存等待loading
const isLoading = ref(false)
// 默认表单数据
const defaultFormData = ref({})
// 表单规则
const rules = ref<FormRules>({
  roleName: [{ required: true, message: '请输入角色名称', trigger: 'blur' }],
  roleKey: [{ required: true, message: '请输入权限字符', trigger: 'blur' }],
})
// 保存
const handleSubmit = (formEl: FormInstance | undefined) => {
  isLoading.value = true
  getAllCheckedData()
  if (!formEl) return
  formEl.validate((valid, fields) => {
    if (valid) {
      if (props.id !== '') {
        updateRole(formData.value).then((res) => {
          ElMessage.success('修改成功')
          isLoading.value = false
          handleCancel()
        }).catch(() => {
          isLoading.value = false
        })
      } else {
        addRole(formData.value).then((res) => {
          ElMessage.success('新增成功')
          isLoading.value = false
          handleCancel()
        }).catch(() => {
          isLoading.value = false
        })
      }
    }
  })
}
// 取消
const handleCancel = () => {
  emit('update:dialogShow', false)
  formData.value = {
    roleName: '',
    roleKey: '',
    status: '0',
    remark: '',
    menu: '',
    roleSort: '',
    menuIds: []
  }
  isDetail.value = false
  defaultCheckedKeys.value = []
  isEdit.value = false
  treeData.value = []
}
// 修改 getAllCheckedData 函数
const getAllCheckedData = () => {
  if (!testingTree.value) return;
  formData.value.menuIds = testingTree.value.getCheckedKeys(false);
}
// 编辑
const handleEdit = () => {
  defaultFormData.value = cloneDeep(formData.value)
  isEdit.value = true
}
function handleCloseTip(done: () => void) {
  if (isDetail.value) {
    // 校验值是否相同
    if (isEqual(defaultFormData.value, formData.value)) {
      handleCancel()
      done()
      return
    }
    ElMessageBox.confirm("当前编辑未保存，是否确定关闭？").then(() => {
      done()
    })
    return
  } else {
    handleCancel()
    done()
  }

}
const sreach = () => {
  if (!props.id) return;
  getRole(props.id).then((res: any) => {
    formData.value = res.data
  })
  roleMenuTreeselect(props.id).then((res: any) => {
    defaultCheckedKeys.value = res.checkedKeys
    treeData.value = res.menus
  })
}
// 监听弹窗
watch(() => props.dialogShow, (newVal) => {
  dialogVisible.value = newVal
  if (props.id !== '') {
    textMap.value = '角色详情'
    isDetail.value = false
    sreach()
  } else {
    textMap.value = '新增角色'
    isDetail.value = true
    defaultFormData.value = cloneDeep(formData.value)
    treeselect().then((res: any) => {
      treeData.value = res.data
      checkedAll.value = false; // 新增时默认不全选
      showAll.value = false; // 折叠状态
    })
  }
})
const isIndeterminate = ref(false)
const handleNodeCheck = () => {
  // 获取Tree组件的实例，使用ref声明的变量在逻辑代码中使 用时需加 .value
  const tree = testingTree.value;

  let checkedCount = 0;//被勾选上的一级节点个数
  let disabledCount = 0;//置灰的一级节点个数
  let indeterminateFlag = false;//有没有一级节点处于半选状态

  //遍历所有一级节点(testingData为el-tree组件：data的值)
  for (let i = 0; i < treeData.value.length; i++) {
    //getNode为el-tree组件的实例方法，可以根据 data 或者 key 拿到 Tree 组件中的 node
    if (tree.getNode(treeData.value[i]).disabled == true) {
      disabledCount += 1;//如果有置灰的节点，置灰变量加1
    }
    if (tree.getNode(treeData.value[i]).checked == true) {
      checkedCount += 1;//如果有勾选的节点，勾选变量加1
    }
    if (tree.getNode(treeData.value[i]).indeterminate == true) {
      indeterminateFlag = true;//如果有半选的节点，半选变量设为true
    }
  }

  if (checkedCount == 0) {
    isIndeterminate.value = false;
    checkedAll.value = false;//如果勾选的一级节点数为0，则设置全选按钮样式不为半选样式，全选的值为false

    if (indeterminateFlag == true) {//如果下面有半选的，设置全选按钮的样式为半选样式
      isIndeterminate.value = true;
      checkedAll.value = false;
    }

  }
  else if ((checkedCount + disabledCount) == treeData.value.length) {//如果树上勾上的和置灰的加起来等于tree上data的长度，设置全选按钮样式不为半选样式，全选值为true
    isIndeterminate.value = false;
    checkedAll.value = true;

  }
  else {//上面条件不满足，则说明没有全部勾上，设置样式为半选，全选值为false
    isIndeterminate.value = true;
    checkedAll.value = false;

  }
}
const handleAllCheckedChange = () => {
  isIndeterminate.value = false;//设置全选按钮样式不为半选
  if (checkedAll.value == true) {
    //如果是当前值是全选，依次遍历节点设置勾选，同时过滤的disabled为true的
    for (let i = 0; i < treeData.value.length; i++) {
      setTimeout(() => {
        testingTree.value.setChecked(treeData.value[i].id, true, true);
      }, 0);
    }

  }
  else {
    //取消全选时置空
    testingTree.value.setCheckedKeys([])
  }
}
const handleExpandChange = () => {
  if (showAll.value) {
    testingTree.value.store._getAllNodes().forEach((node: any) => {
      node.expanded = true;
    })
  } else {
    testingTree.value.store._getAllNodes().forEach((node: any) => {
      node.expanded = false;
    })
  }
}
const isEdit = ref(false)
/**
 * 取消编辑
 */
const handleEditCancel = () => {
  sreach()
  isEdit.value = false;
}
</script>
<template>
  <div>
    <el-drawer v-model="dialogVisible" :show-close="false" :before-close="handleCloseTip"
      @close-auto-focus="handleCancel" @close="handleCancel" :size="700">
      <template #header>
        <h4>{{ textMap }}</h4>
        <el-space justify="end">
          <!-- 详情页面 -->
          <template v-if="!isDetail">
            <!-- 编辑状态：显示取消保存和保存按钮 -->
            <el-button v-if="isEdit" @click="handleEditCancel">
              取消保存
            </el-button>
            <el-button v-if="isEdit" type="primary" :loading="isLoading" v-throttle="() => handleSubmit(ruleFormRef)">
              保存
            </el-button>
            <!-- 非编辑状态：显示编辑按钮 -->
            <el-button v-if="!isEdit" type="primary" @click="handleEdit">
              编辑
            </el-button>
          </template>

          <!-- 上传页面：只显示保存按钮 -->
          <template v-else>
            <el-button type="primary" :loading="isLoading" v-throttle="() => handleSubmit(ruleFormRef)">
              保存
            </el-button>
          </template>
        </el-space>
      </template>
      <div v-show="isDetail || isEdit" class="cpi-content nobac">
        <el-form :model="formData" label-width="100px" :rules="rules" ref="ruleFormRef">
          <el-form-item label="角色名称" prop="roleName">
            <el-input v-model="formData.roleName" />
          </el-form-item>
          <el-form-item label="显示顺序">
            <el-input v-model="formData.roleSort" />
          </el-form-item>
          <el-form-item label="权限字符" prop="roleKey">
            <el-input v-model="formData.roleKey" />
          </el-form-item>
          <el-form-item label="备 注">
            <el-input v-model="formData.remark" />
          </el-form-item>
          <el-form-item label="角色状态">
            <el-switch v-model="formData.status" active-value="1" inactive-value="0" />
          </el-form-item>
          <el-form-item label="菜单权限">
            <div>
              <el-checkbox v-model="checkedAll" :indeterminate="isIndeterminate"
                @change="handleAllCheckedChange">全选</el-checkbox>
              <el-checkbox v-model="showAll" @change="handleExpandChange">展开/折叠</el-checkbox>
            </div>
            <div style="width: 100%;">
              <el-tree style="width: 100%" node-key="id" :default-checked-keys="defaultCheckedKeys" :data="treeData"
                ref="testingTree" :props="defaultProps" show-checkbox @check-change="handleNodeCheck" />
            </div>
          </el-form-item>
        </el-form>
      </div>
      <div v-show="!isDetail && !isEdit" class="cpi-content-detail">
        <el-form :model="formData" label-width="100px">
          <el-form-item label="角色名称" prop="roleName">
            {{ formData.roleName }}
          </el-form-item>
          <el-form-item label="显示顺序">
            {{ formData.roleSort }}
          </el-form-item>
          <el-form-item label="权限字符" prop="roleKey">
            {{ formData.roleKey }}
          </el-form-item>
          <el-form-item label="备 注">
            {{ formData.remark }}
          </el-form-item>
          <el-form-item label="角色状态">
            {{ formData.status === '0' ? '正常' : '停用' }}
          </el-form-item>
          <el-form-item label="菜单权限">
            <div style="width: 100%;">
              <el-tree style="width: 100%" :class="isDetail ? '' : 'disabled-tree'" show-checkbox :data="treeData"
                :default-checked-keys="defaultCheckedKeys" node-key="id" :props="defaultProps" @check="handleNodeCheck"
                :disabled="!isDetail" />
            </div>
          </el-form-item>
        </el-form>
      </div>
      <template #footer>
        <div class="dialog-footer">
          <el-button @click="handleCancel">退 出</el-button>
        </div>
      </template>
    </el-drawer>
  </div>
</template>

<style lang="scss" scoped>
:deep(.disabled-tree) {
  .el-checkbox {
    pointer-events: none;
    cursor: not-allowed;
  }

  .el-checkbox__input {
    .el-checkbox__inner {
      // 禁用的样式
      background-color: rgb(237, 242, 252);
      border-color: rgb(217, 217, 217);
    }

    &.is-checked {

      // 勾选状态下的样式,不加的话禁用时勾选是灰色的
      .el-checkbox__inner:after {
        border-color: rgb(0, 91, 255);
      }

      // .el-checkbox__inner {
      //   background-color: rgb(0, 91, 255);
      //   // border-color: rgb(0, 91, 255);
      // }
    }
  }
}

.mb-6 {
  margin-bottom: 10px;
}
</style>
